/*-----------------------------------------------------------------------------
		   Licensed to the Apache Software Foundation (ASF) under one
           or more contributor license agreements.  See the NOTICE file
           distributed with this work for additional information
           regarding copyright ownership.  The ASF licenses this file
           to you under the Apache License, Version 2.0 (the
           "License"); you may not use this file except in compliance
           with the License.  You may obtain a copy of the License at

             http://www.apache.org/licenses/LICENSE-2.0

           Unless required by applicable law or agreed to in writing,
           software distributed under the License is distributed on an
           "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
           KIND, either express or implied.  See the License for the
           specific language governing permissions and limitations
           under the License.  
-----------------------------------------------------------------------------*/

package languages;

/**
 * This class represents the commonality between programming languages, there
 * are fields which are specified to languages as well as methods. 
 * 
 * @author Kevin.J.Jalbert
 */
public class ProgrammingLanguage {

	protected String START_LINE_COMMENT = "";
	protected String END_LINE_COMMENT = "";
	protected String START_BLOCK_COMMENT = "";
	protected String END_BLOCK_COMMENT = "";
	protected String SINGLE_QUOTES = "";
	protected String DOUBLE_QUOTES = "";
	protected String ESCAPE = "";
	private boolean lineComment = false;
	private boolean blockComment = false;
	private boolean singleQuote = false;
	private boolean doubleQuote = false;
	private boolean escape = false;

	public final int BUFFER_SIZE = 5; // Buffer size to increase speed

	private String currentBuffer = ""; // The current buffer of characters
	private int removedCharacters = 0; // The amount of characters that might be removed
	private String lastAction = ""; // The last action that was used

	/**
	 * Instantiates a new programming language.
	 */
	public ProgrammingLanguage(){

	}

	/**
	 * Adds the a character to the internal buffer.
	 * 
	 * @param character the character to be added to the character
	 */
	public void addToBuffer(String character) {
		currentBuffer = currentBuffer.concat(character);

		// If the buffer is getting larger then buffer size remove all but last 2
		if(currentBuffer.length() == BUFFER_SIZE){
			currentBuffer = currentBuffer.substring(BUFFER_SIZE- 2);
			removedCharacters += BUFFER_SIZE- 2;
		}
	}

	/**
	 * Check for a possible character match to one of the defined syntax, if
	 * there is a match make note of the action.
	 * 
	 * @return true, if successful
	 */
	public boolean characterMatch() {
		boolean valid = false; 
		// Check for case where character is in a block comment
		if (isBlockComment()){
			if(currentBuffer.contains(END_BLOCK_COMMENT)){
				setBlockComment(false);
				lastAction = END_BLOCK_COMMENT;
				valid = true;
			}
		}
		// Check for a case where character is in a line comment
		else if (isLineComment()){
			if(currentBuffer.contains(END_LINE_COMMENT)){
				setLineComment(false);
				lastAction = END_LINE_COMMENT;
				valid = true;
			}
		}
		// Check for case where character is in double quotes
		else if (isDoubleQuote()){
			if (currentBuffer.contains(ESCAPE)){
				setEscape(true);
				lastAction = ESCAPE;
				valid = true;
			}
			else if (currentBuffer.contains(DOUBLE_QUOTES)){
				setDoubleQuote(false);
				lastAction = DOUBLE_QUOTES;
				valid = true;
			}
		}
		// Check for case where character is in single quotes
		else if (isSingleQuote()){
			if (currentBuffer.contains(ESCAPE)){
				setEscape(true);
				lastAction = ESCAPE;
				valid = true;
			}
			else if (currentBuffer.contains(SINGLE_QUOTES)){
				setSingleQuote(false);
				lastAction = SINGLE_QUOTES;
				valid = true;
			}
		}
		// Check for case where character is valid, is starting a comment
		else{
			if (currentBuffer.contains(START_LINE_COMMENT)){
				setLineComment(true);
				lastAction = START_LINE_COMMENT;
				valid = true;
			}
			else if (currentBuffer.contains(START_BLOCK_COMMENT)){
				setBlockComment(true);
				lastAction = START_BLOCK_COMMENT;
				valid = true;
			}			
		}
		// valid is true if a match was found
		return valid;
	}

	/**
	 * Gets the number of characters that were removed; this is the buffer's
	 * true size as the current buffer, number of removed characters and the last
	 * action's length are used.
	 * 
	 * @return the removed characters
	 */
	public int getRemovedCharacters() {
		int numberRemoved = currentBuffer.length() + removedCharacters - lastAction.length();

		// Reset these fields
		currentBuffer = "";
		removedCharacters = 0;
		lastAction = "";

		return numberRemoved;
	}

	/**
	 * Checks if the last action was an ending of a comment.
	 * 
	 * @return valid this is true if the end of a comment was last
	 */
	public boolean isCommentEnd() {
		boolean valid = false;

		// Check to see if a comment ended
		if(lastAction.equals(END_BLOCK_COMMENT) || lastAction.equals(END_LINE_COMMENT)){
			valid = true;
		}

		return valid;
	}

	/**
	 * Checks if the last action was a starting of a comment.
	 * 
	 * @return valid this is true if the start of a comment was last
	 */
	public boolean isCommentStart() {
		boolean valid = false;

		// Check to see if a comment started
		if(lastAction.equals(START_BLOCK_COMMENT) || lastAction.equals(START_LINE_COMMENT)){
			valid = true;
		}

		return valid;
	}

	/**
	 * Checks if state is in a block comment.
	 * 
	 * @return true, if state is in a block comment
	 */
	public boolean isBlockComment() {
		return this.blockComment;
	}

	/**
	 * Checks if state is in a double quote.
	 * 
	 * @return true, if state is in a double quote
	 */
	public boolean isDoubleQuote() {
		return this.doubleQuote;
	}

	/**
	 * Checks if state is in an escape.
	 * 
	 * @return true, if state is in an escape
	 */
	public boolean isEscape() {
		return this.escape;
	}

	/**
	 * Checks if state is in a line comment.
	 * 
	 * @return true, if state is in a line comment
	 */
	public boolean isLineComment() {
		return this.lineComment;
	}

	/**
	 * Checks if state is in a single quote.
	 * 
	 * @return true, if state is in a single quote
	 */
	public boolean isSingleQuote() {
		return this.singleQuote;
	}

	/**
	 * Sets the block comment state.
	 * 
	 * @param blockComment the new block comment state
	 */
	public void setBlockComment(boolean blockComment) {
		this.blockComment = blockComment;
	}

	/**
	 * Sets the double quote state.
	 * 
	 * @param doubleQuote the new double quote state
	 */
	public void setDoubleQuote(boolean doubleQuote) {
		this.doubleQuote = doubleQuote;		
	}

	/**
	 * Sets the escape state.
	 * 
	 * @param escape the new escape state
	 */
	public void setEscape(boolean escape) {
		this.escape = escape;
	}

	/**
	 * Sets the line comment state.
	 * 
	 * @param lineComment the new line comment state
	 */
	public void setLineComment(boolean lineComment) {
		this.lineComment = lineComment;
	}

	/**
	 * Sets the single quote state.
	 * 
	 * @param singleQuote the new single quote state
	 */
	public void setSingleQuote(boolean singleQuote) {
		this.singleQuote = singleQuote;		
	}
}